package com.padgett.resourcemanagement.report;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.labs.repackaged.org.json.JSONException;
import com.google.appengine.labs.repackaged.org.json.JSONObject;
import com.padgett.resourcemanagement.data.ClientDAO;
import com.padgett.resourcemanagement.util.ClientNameSortable;
import com.padgett.resourcemanagement.util.SystemConstants;

/**
 * Shows planned billing (services) and actual billed (Included in invoice).
 * Shows running date and user.  Planned billing shows running month regardless
 * of completeness.  For Admin, it shows by user by client.
 * 
 * Collect all services by clients due this month
 * Collect all clients by current user
 * Collect all invoices issued this month
 * Collect all services by invoices that due this month
 * Differentiate planned and actual.
 * 
 * @author andyleung
 * 
 */
@SuppressWarnings("serial")
public class PerformanceReport extends HttpServlet{
	@SuppressWarnings("unchecked")
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException, ServletException {
		UserService userService=UserServiceFactory.getUserService();
		User user=userService.getCurrentUser();
		// Determine if this is admin or user
		Key userKey=new KeyFactory.Builder("User",user.getUserId()).getKey();
		Entity userEntity=ClientDAO.loadEntity(userKey);
		boolean isAdmin=false;
		if(((String)userEntity.getProperty("Role")).equalsIgnoreCase("admin")){
			isAdmin=true;
		}
		GregorianCalendar today=new GregorianCalendar();
		today.setTimeInMillis(System.currentTimeMillis());
		List<Entity> services=ClientDAO.getAllServicesDuedByMonth(today.get(GregorianCalendar.MONTH));
		// Build service map using client ID
		List<Key> clientKeys=new ArrayList<Key>();
		Map<Key,List<Entity>> clientServiceMap=new HashMap<Key,List<Entity>>();
		for(Entity service:services){
			Key serviceClientKey=(Key)service.getProperty("Client");
			if(clientServiceMap.containsKey(serviceClientKey)){
				List<Entity> clientServices=clientServiceMap.get(serviceClientKey);
				clientServices.add(service);
			}else{
				List<Entity> clientServices=new ArrayList<Entity>();
				clientServices.add(service);
				clientServiceMap.put(serviceClientKey, clientServices);
			}
		}
		
		/*
		for(Entity service:services){
			// Get client name
			clientKeys.add((Key)service.getProperty("Client"));
			// Get invoice items by serviceid
			List<Entity> invoiceLineItems=ClientDAO.getInvoiceLineItemsByServices(service.getKey());
		}*/
		Map<Key,Entity> clientMap=ClientDAO.getClientsByKeys(clientKeys);
		JSONObject response=new JSONObject();
		List<JSONObject> clients=new ArrayList<JSONObject>();
		List<ClientNameSortable> sortedClientList=new ArrayList<ClientNameSortable>();
		Iterator<Entry<Key, Entity>> clientIterator=clientMap.entrySet().iterator();
		while(clientIterator.hasNext()){
			Map.Entry<Key,Entity> entry=(Map.Entry<Key,Entity>)clientIterator.next();
			sortedClientList.add(new ClientNameSortable(KeyFactory.keyToString(entry.getKey()),(String)entry.getValue().getProperty("Name")));
		}
		// Sort client list by name
		Collections.sort(sortedClientList);
		try{
			response.put("NumberOfClients", sortedClientList.size());
			double totalPlannedBilling=0.0;
			double totalActualBilling=0.0;
			double plannedBilling=0.0;
			double actualBilling=0.0;
			for(ClientNameSortable sortedClient:sortedClientList){
				plannedBilling=0.0;
				actualBilling=0.0;
				// For each client name, use key to get service
				JSONObject client=new JSONObject();
				client.put("Key",sortedClient.getClientId());
				client.put("Name",sortedClient.getName());
				List<Entity> clientServices=clientServiceMap.get(KeyFactory.stringToKey(sortedClient.getClientId()));
				if(clientServices!=null&&!clientServices.isEmpty()){
					for(Entity service:clientServices){
						boolean billed=(Boolean)(service.getProperty("Billed")!=null?service.getProperty("Billed"):Boolean.FALSE);
						double amount=(service.getProperty("Amount")!=null?(Double)service.getProperty("Amount"):0.0);
						plannedBilling+=amount;
						totalPlannedBilling+=plannedBilling;
						if(billed){
							actualBilling+=amount;
							totalActualBilling+=actualBilling;
						}
					}
				}
				client.put("PlannedBilling", plannedBilling);
				client.put("ActualBilling",actualBilling);
				clients.add(client);
			}
			response.put("TotalPlannedBilling", totalPlannedBilling);
			response.put("TotalActualBilling", totalActualBilling);
			response.put("Clients", clients);
			req.setAttribute("Report", response);
		}catch(JSONException je){
			je.printStackTrace();
		}
		if(isAdmin){
			// Generate report by each user by client.
		}else{
			// Generate report by client for current user.
			
		}
		req.setAttribute("CurrentUserId", user.getUserId());
		String page=SystemConstants.PERFORMANCE_REPORT_PAGE;
		RequestDispatcher dispatcher=req.getRequestDispatcher(page);
		dispatcher.forward(req, resp);
	}
}
